#include "EstrategiaMovimientoFantasma.h"
#include "EscenarioModelo.h"
#include "IteradorLista.h"

bool EstrategiaMovimientoFantasma::existeEncrusijada(Punto* unPunto){

    Punto *arriba = new Punto( unPunto->getX(), unPunto->getY()-1);
	Punto *abajo = new Punto( unPunto->getX(), unPunto->getY()+1);
	Punto *derecha = new Punto( unPunto->getX()+1, unPunto->getY());
	Punto *izquierda = new Punto( unPunto->getX()-1, unPunto->getY());
	
	bool retorno = false;

	if(this->direccionActual->esDerecha() || this->direccionActual->esIzquierda()){
		retorno = (EscenarioModelo::getEscenario()->perteneceAlSendero(abajo) || EscenarioModelo::getEscenario()->perteneceAlSendero(arriba));
		if(this->direccionActual->esIzquierda()){
			retorno = (!EscenarioModelo::getEscenario()->perteneceAlSendero(izquierda) || retorno);
		}else{
			retorno = (!EscenarioModelo::getEscenario()->perteneceAlSendero(abajo) || retorno);
		}
	
	}else{
		retorno = (EscenarioModelo::getEscenario()->perteneceAlSendero(derecha) || EscenarioModelo::getEscenario()->perteneceAlSendero(izquierda));
		if(this->direccionActual->esArriba()){
			retorno = (!EscenarioModelo::getEscenario()->perteneceAlSendero(arriba) || retorno);
		}else{
			retorno = (!EscenarioModelo::getEscenario()->perteneceAlSendero(abajo) || retorno);
		}
	}
	
	delete arriba;
	delete abajo;
	delete izquierda;
	delete derecha ;

	return retorno;
}

Direccion* EstrategiaMovimientoFantasma::getDireccion(){
	return this->direccionActual ;
}

void EstrategiaMovimientoFantasma::setPresa(ObjetoVivo* unaPresa){
    this->presa = unaPresa;
}

EstrategiaMovimientoFantasma::EstrategiaMovimientoFantasma(ObjetoVivo *unaPresa, Direccion* unaDireccion, unsigned short velocidad)
    : EstrategiaMovimiento(velocidad){
	this->presa = unaPresa;
    this->cantidadMovidas = 0;
    this->puntoPacman = NULL;
    this->direccionActual = unaDireccion;
	this->direccionAnterior = 0;
    this->contadorMovimiento = 0;
    
}


Punto* EstrategiaMovimientoFantasma::calcularMasCercano(Lista<Punto>* lista, Punto* puntoActual, Punto* puntoPacman){
	
    Punto *masCercano = puntoActual;
	int menorDistancia = 999999999;  //tiene 9 nueves, si es mayor aparece warning

	IteradorLista<Punto>* itPuntosPosibles = new IteradorLista<Punto>(lista); 

	while(itPuntosPosibles->tieneSiguiente()){
		Punto* pto = itPuntosPosibles->siguiente();
		int distancia = (int)puntoPacman->getDistancia(pto); 
		if( distancia < menorDistancia){
			masCercano = pto ;
			menorDistancia = distancia;
		}
	}
	return masCercano ;

}


ObjetoVivo* EstrategiaMovimientoFantasma::getPresa(){
	return this->presa ;
}

// Dado un punto me devuelve los posibles puntos, las 4 coordenadas
Lista<Punto>* EstrategiaMovimientoFantasma::getListaPuntos(Punto* punto){
        Punto *arriba = new Punto( punto->getX(), punto->getY()-1);
		Punto *abajo = new Punto( punto->getX(), punto->getY()+1);
		Punto *derecha = new Punto( punto->getX()+1, punto->getY());
		Punto *izq = new Punto( punto->getX()-1, punto->getY());
		Lista<Punto>* lista = new Lista<Punto>();

		lista->agregar(arriba);
		lista->agregar(abajo);
		lista->agregar(derecha);
		lista->agregar(izq);
		return lista;
}

// Dado un pto, devuelve de los 4 movimientos solo los posibles segun el sendero
Lista<Punto>* EstrategiaMovimientoFantasma::getListaPuntosPosibles(Punto* punto){
	Lista<Punto>* lista = this->getListaPuntos(punto);
	IteradorLista<Punto>* it = new IteradorLista<Punto>(lista);
	Lista<Punto>* res = new Lista<Punto>();
	while(it->tieneSiguiente()){
		Punto* pto = it->siguiente();
		if(EscenarioModelo::getEscenario()->perteneceAlSendero(pto))
			res->agregar(new Punto(pto));
	}
	delete lista;
	return res;

}

void EstrategiaMovimientoFantasma::actualizarDirecciones(Punto* antes, Punto* despues){
	if(this->direccionAnterior)
			delete this->direccionAnterior;

	this->direccionAnterior = this->direccionActual ;
	this->direccionActual = Direccion::calcularDireccion(antes,despues);
}


Punto* EstrategiaMovimientoFantasma::moverVirtual(Punto* unPunto){
	Punto* nuevaPosicion = new Punto(unPunto);

    //if(this->existeEncrusijada(unPunto)){
    this->decidirNuevaDireccion(unPunto);
    //}

    switch (this->direccionActual->getDireccion()){
        case Direccion::ARRIBA :
            nuevaPosicion->decrementarY();
            break;
        case Direccion::ABAJO :
            nuevaPosicion->incrementarY();
            break;
        case Direccion::DERECHA :
            nuevaPosicion->incrementarX();
            break;
        case Direccion::IZQUIERDA :
			nuevaPosicion->decrementarX();
            break;
    }
    return  nuevaPosicion;
}

EstrategiaMovimientoFantasma::~EstrategiaMovimientoFantasma(){
	delete this->puntoPacman;
	delete this->direccionActual;
}